#include "includes.h"
#include "sys.h"
#include "tools.h"
#include "sys_timer.h"

#define SYMBOL_GLOBALS
#include "rtc.h"
#undef SYMBOL_GLOBALS

//* rtc模块初始化
void RTCInit(void)
{
	INT32U usTimeout = 0;
	INT16U usBKPVal;
	
	//* 使能后备寄存器访问  
	PWR_BackupAccessCmd(ENABLE);	
	
	//* 检查是不是第一次配置时钟，依据是从指定的后备寄存器中读出数据，如果读出数据与写入数据不相符
	usBKPVal = BKP_ReadBackupRegister(BKP_DR1);
	if(usBKPVal != 0x5050)
	{	 					
		//* 复位备份区域
		BKP_DeInit();
				
		RCC_LSEConfig(RCC_LSE_ON);													//* 设置外部低速晶振(LSE),使用外设低速晶振
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	//* 检查指定的RCC标志位设置与否,等待低速晶振就绪
		{				
			usTimeout++;
			DelaymsByCount(10);
		}
		
		//* 超过一定时间则认为初始化失败，外部晶振有问题？
		if(usTimeout >= 250)
			return;	    
		
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//* 设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);										//* 使能RTC时钟  
		RTC_WaitForLastTask();										//* 等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();											//* 等待RTC寄存器同步  
		RTC_ITConfig(RTC_IT_SEC, ENABLE);					//* 使能RTC秒中断
		RTC_WaitForLastTask();										//* 等待最近一次对RTC寄存器的写操作完成
		RTC_EnterConfigMode();										//* 允许配置	
		RTC_SetPrescaler(32767); 									//* 设置RTC预分频的值
		RTC_WaitForLastTask();										//* 等待最近一次对RTC寄存器的写操作完成
		RTCSetSysTime(2020, 03, 13, 21, 58, 10); 	//* 设置系统初始时间	
		RTC_ExitConfigMode(); 										//* 退出配置模式  
		BKP_WriteBackupRegister(BKP_DR1, 0x5050);	//* 向指定的后备寄存器中写入用户程序数据
	}
	//* 系统继续计时
	else
	{
		RTC_WaitForSynchro();								//* 等待最近一次对RTC寄存器的写操作完成
		//RTC_ITConfig(RTC_IT_SEC, ENABLE);	//* 使能RTC秒中断
		RTC_WaitForLastTask();							//* 等待最近一次对RTC寄存器的写操作完成
	}
}

//* -------------------------------------------------------------
//* 判断是否是闰年：
//* 月份   1  2  3  4  5  6  7  8  9  10 11 12
//* 闰年   31 29 31 30 31 30 31 31 30 31 30 31
//* 非闰年 31 28 31 30 31 30 31 31 30 31 30 31
static BOOL IsLeapYear(INT16U usYear)
{			  
	//* 必须能被4整除
	if(usYear % 4 == 0)
	{ 
		//* 如果以00结尾,还要能被400整除
		if(usYear % 100 == 0) 
		{ 
			if(usYear % 400 == 0)
				return 1;
			else 
				return 0;   
		}
		else
			return 1;   
	}
	else
		return 0;	
}

//* -------------------------------------------------------------
//* 设置时钟，把输入的时钟转换为秒钟，以1970年1月1日为基准，1970~2099年为合法年份
//* -------------------------------------------------------------
static const INT8U ubaMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //* 平年的月份日期表
void RTCSetSysTime(INT16U usYear, INT8U ubMonth, INT8U ubDay, INT8U ubHour, INT8U ubMin, INT8U ubSec)
{
	INT32U i;
	INT32U unUnixTime = 0;
	if(usYear < 1970 || usYear > 2099)
		return;
	
	//* 把所有年份的秒钟相加
	for(i=1970; i<usYear; i++)
	{
		if(IsLeapYear(i))
			unUnixTime += 31622400;	//* 闰年的秒钟数
		else 
			unUnixTime += 31536000;	//* 平年的秒钟数
	}
	
	//* 把前面月份的秒钟数相加，扣除当月
	ubMonth -= 1;
	for(i=0; i<ubMonth; i++)
	{
		unUnixTime += (INT32U)ubaMonth[i] * 86400;	//* 月份秒钟数相加
		if(IsLeapYear(usYear) && i == 1)
			unUnixTime += 86400;											//* 闰年2月份增加一天的秒钟数	   
	}
	
	unUnixTime += (INT32U)(ubDay - 1) * 86400;		//* 把前面日期的秒钟数相加
	unUnixTime += (INT32U)ubHour * 3600;					//* 小时秒钟数
	unUnixTime += (INT32U)ubMin * 60;	 						//* 分钟秒钟数
	unUnixTime += ubSec;													//* 最后的秒钟加上去

	//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	PWR_BackupAccessCmd(ENABLE);	//* 使能RTC和后备寄存器访问 
	RTC_SetCounter(unUnixTime);		//* 设置RTC计数器的值

	RTC_WaitForLastTask();				//* 等待最近一次对RTC寄存器的写操作完成  	   
}

void RTCSetSysTimeBCD(INT8U *pubBCDTime)
{
	ST_DATETIME stDateTime;
	
	stDateTime.usYear  = BCDToDecimal(pubBCDTime[0]) * 100 + BCDToDecimal(pubBCDTime[1]);
	stDateTime.ubMonth = BCDToDecimal(pubBCDTime[2]);
	stDateTime.ubDay   = BCDToDecimal(pubBCDTime[3]);
	stDateTime.ubHour  = BCDToDecimal(pubBCDTime[4]);
	stDateTime.ubMin   = BCDToDecimal(pubBCDTime[5]);
	stDateTime.ubSec   = BCDToDecimal(pubBCDTime[6]);

	RTCSetSysTime(stDateTime.usYear, stDateTime.ubMonth, stDateTime.ubDay, stDateTime.ubHour, stDateTime.ubMin, stDateTime.ubSec);
}

INT8U RTCSetSystimeASCII(const char *pszASCIITime, INT8U ubASCIIDecimalLen)
{
	INT8U ubaBCDTime[7], ubBCDTimeLen;
	
	ubBCDTimeLen = ASCIIDecimalToBCDDecimal(pszASCIITime, ubASCIIDecimalLen, ubaBCDTime, sizeof(ubaBCDTime));
	if(ubBCDTimeLen != 7)
		return 1;
	
	if(ubaBCDTime[0] != 0x20 || ubaBCDTime[1] > 0x35 || ubaBCDTime[1] < 0x19 || ubaBCDTime[2] > 0x12 || ubaBCDTime[2] < 0x01 || 
		 ubaBCDTime[3] > 0x31  || ubaBCDTime[3] < 0x01 || ubaBCDTime[4] > 0x23 || ubaBCDTime[5] > 0x59 || ubaBCDTime[6] > 0x59)
		return 2;
	
	RTCSetSysTimeBCD(ubaBCDTime);
	
	return 0;
}

void RTCSetSystemUnixTimestamp(time_t tUnixTimestamp)
{
	struct tm stTime;
	memcpy(&stTime, localtime((time_t*)&tUnixTimestamp), sizeof(struct tm));
	RTCSetSysTime(stTime.tm_year + 1900, stTime.tm_mon + 1, stTime.tm_mday, stTime.tm_hour, stTime.tm_min, stTime.tm_sec);
}

void RTCUnixTimestampToTime(time_t tUnixTimestamp, PST_DATETIME pstDateTime)
{
	struct tm stTime;
	memcpy(&stTime, localtime((time_t*)&tUnixTimestamp), sizeof(struct tm));
	
	pstDateTime->usYear  = stTime.tm_year + 1900;
	pstDateTime->ubMonth = stTime.tm_mon + 1;
	pstDateTime->ubDay   = stTime.tm_mday;
	pstDateTime->ubHour  = stTime.tm_hour;
	pstDateTime->ubMin   = stTime.tm_min;
	pstDateTime->ubSec   = stTime.tm_sec;	
}

void UnixTimeToLocalTime(time_t tUnixTimestamp, INT8S *pszDatetime)
{
  struct tm stTime;    
  localtime_r((time_t*)&tUnixTimestamp, &stTime);

  sprintf((char *)pszDatetime, "%d-%02d-%02d %02d:%02d:%02d", stTime.tm_year + 1900, stTime.tm_mon + 1, stTime.tm_mday, stTime.tm_hour, stTime.tm_min, stTime.tm_sec); 
}

//* 获取系统当前时间
void RTCGetSysTime(PST_DATETIME pstDateTime)
{
	static INT32U unPrevDayCount = 0;
	static INT8U ubMonth, ubDay;
	INT32U unRTCCounter, unCurDays, unCurSecs;
	static INT16U usYear;
	
	//* 读取RTC当前秒计数
	unRTCCounter = RTC_GetCounter();
		
	unCurDays = unRTCCounter / 86400;		//* 得到秒钟数对应的天数
	if(unPrevDayCount != unCurDays)			//* 与之前的日计数相比，不相等，则肯定超过一天了
	{
		unPrevDayCount = unCurDays;
		
		usYear = 1970;
		while(unCurDays >= 365)
		{				 
			//* 如果是闰年
			if(IsLeapYear(usYear))
			{
				if(unCurDays >= 366)
					unCurDays -= 366; //* 闰年的天数
				else
				{
					usYear++;
					break;
				}  
			}
			//* 如果是平年 
			else 
				unCurDays -= 365;
			usYear++;  
		}  		
		
		ubMonth = 0;
		while(unCurDays >= 28)	//* 超过了一个月
		{
			//* 闰年且是2月
			if(IsLeapYear(usYear) && ubMonth == 1)
			{
				if(unCurDays >= 29)
					unCurDays -= 29; //* 闰年2月的天数
				else
					break; 
			}
			else 
			{
				if(unCurDays >= ubaMonth[ubMonth])
					unCurDays -= ubaMonth[ubMonth];
				else 
					break;
			}
			
			ubMonth++;  
		}
		
		ubMonth += 1;
		ubDay = unCurDays + 1;	//* 得到日期 		
	}
	
	pstDateTime->usYear  = usYear;	//* 得到了年份
	pstDateTime->ubMonth = ubMonth;	//* 得到月份
	pstDateTime->ubDay   = ubDay;		//* 得到日期 
	
	unCurSecs = unRTCCounter % 86400;							//* 得到当天的秒数
	pstDateTime->ubHour = unCurSecs / 3600;    		//* 小时
	pstDateTime->ubMin = (unCurSecs % 3600) / 60;	//* 分	
	pstDateTime->ubSec = (unCurSecs % 3600) % 60;	//* 秒
}

void RTCGetSysTimeBCD(INT8U *pubBCDTime)
{	
	INT8U ubaBCDVal[2];
	ST_DATETIME stDateTime;
		
	RTCGetSysTime(&stDateTime);
	
	//* 年
	DecimalToBCD(stDateTime.usYear, ubaBCDVal, 2);	
	pubBCDTime[0] = ubaBCDVal[0];
	pubBCDTime[1] = ubaBCDVal[1];
	
	//* 月
	DecimalToBCD(stDateTime.ubMonth, ubaBCDVal, 1);	
	pubBCDTime[2] = ubaBCDVal[0];
	
	//* 日
	DecimalToBCD(stDateTime.ubDay, ubaBCDVal, 1);	
	pubBCDTime[3] = ubaBCDVal[0];
	
	//* 时
	DecimalToBCD(stDateTime.ubHour, ubaBCDVal, 1);	
	pubBCDTime[4] = ubaBCDVal[0];
	
	//* 分
	DecimalToBCD(stDateTime.ubMin, ubaBCDVal, 1);	
	pubBCDTime[5] = ubaBCDVal[0];
	
	//* 秒
	DecimalToBCD(stDateTime.ubSec, ubaBCDVal, 1);	
	pubBCDTime[6] = ubaBCDVal[0];
}

INT32U RTCGetDaySystimeDecimal(void)
{
	ST_DATETIME stDateTime;
	INT32U unDayTimeDecimal;
	char szDecimal[10];
		
	RTCGetSysTime(&stDateTime);
	
	sprintf(szDecimal, "%02d%02d%02d", stDateTime.ubHour, stDateTime.ubMin, stDateTime.ubSec);
	unDayTimeDecimal = atoi(szDecimal);	
	return unDayTimeDecimal;
}

time_t UnixTimestamp(PST_DATETIME pstDateTime)
{
	struct tm stTM;
	stTM.tm_year = pstDateTime->usYear - 1900;
	stTM.tm_mon = pstDateTime->ubMonth - 1;
	stTM.tm_mday = pstDateTime->ubDay;
	stTM.tm_hour = pstDateTime->ubHour;
	stTM.tm_min = pstDateTime->ubMin;
	stTM.tm_sec = pstDateTime->ubSec;
	
	return mktime(&stTM);
}

time_t Time(void)
{
	ST_DATETIME stDateTime;
	
	RTCGetSysTime(&stDateTime);
	
	return UnixTimestamp(&stDateTime);
}
